/**
 * @file    wifi_eth.c
 * @author  Azolla (1228449928@qq.com)
 * @brief
 * @version 0.1
 * @date    2022-10-19
 * 
 * @copyright Copyright (c) 2022
 * */
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_netif.h"
#include "esp_eth.h"
#include "esp_event.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "sdkconfig.h"

#include "lwip/err.h"
#include "lwip/sockets.h"

#include "mdf_common.h"
#include "mwifi.h"
 
#include "driver/spi_master.h"


#define TAG   "wifi_eth"

/*****************************************
GPIO	W5500
GPIO14	SPI_CLK
GPIO13	SPI_MOSI
GPIO12	SPI_MISO
GPIO15	SPI_CS
GPIO4	Interrupt
GPIO22	Reset
***************************************/
#define CONFIG_USE_W5500                1
#define CONFIG_ETH_SPI_HOST             SPI2_HOST
#define CONFIG_ETH_SPI_CLOCK_MHZ        20
#define CONFIG_ETH_SPI_SCLK_GPIO        18
#define CONFIG_ETH_SPI_MOSI_GPIO        16
#define CONFIG_ETH_SPI_MISO_GPIO        17
#define CONFIG_ETH_SPI_CS0_GPIO         8
#define CONFIG_ETH_SPI_INT0_GPIO        15
#define CONFIG_ETH_SPI_PHY_RST0_GPIO    7
#define CONFIG_ETH_SPI_PHY_ADDR0        1

static esp_eth_handle_t eth_handle = NULL;
static esp_netif_t *eth_netif = NULL; 

/** Event handler for Ethernet events */
static void eth_event_handler(void *arg, esp_event_base_t event_base,
                              int32_t event_id, void *event_data)
{
    uint8_t mac_addr[6] = {0};
    /* we can get the ethernet driver handle from event data */
    esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;

    switch (event_id) {
    case ETHERNET_EVENT_CONNECTED:
        #ifdef TAG
        esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr);
        ESP_LOGI(TAG, "Ethernet Link Up");
        ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x",
                 mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
        #endif
        break;
    case ETHERNET_EVENT_DISCONNECTED:
        #ifdef TAG
        ESP_LOGI(TAG, "Ethernet Link Down");
        #endif
        
        mdf_event_loop_send(MDF_EVENT_MWIFI_PARENT_DISCONNECTED, NULL);  // 断开连接
        break;
    case ETHERNET_EVENT_START:
        #ifdef TAG
        ESP_LOGI(TAG, "Ethernet Started");
        #endif  
        break;
    case ETHERNET_EVENT_STOP:
        #ifdef TAG
        ESP_LOGI(TAG, "Ethernet Stopped");
        #endif
        mdf_event_loop_send(MDF_EVENT_MWIFI_PARENT_DISCONNECTED, NULL);  // 断开连接
        break;
    default:
        break;
    }
}
 


/** Event handler for IP_EVENT_ETH_GOT_IP */
static void ip_event_handler(void *arg, esp_event_base_t event_base,
                            int32_t event_id, void *event_data)
{
    // event_base == ETH_EVENT
    switch (event_id) {
        case IP_EVENT_ETH_GOT_IP: {
            ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data;
            const esp_netif_ip_info_t *ip_info = &event->ip_info;
            #ifdef TAG
            MDF_LOGI("~~~~~~~~~~~~~~~~~~~~~~~~~");
            MDF_LOGI("Ethernet Got IP Address");
            MDF_LOGI("ETHIP:" IPSTR, IP2STR(&ip_info->ip));
            MDF_LOGI("ETHMASK:" IPSTR, IP2STR(&ip_info->netmask));
            MDF_LOGI("ETHGW:" IPSTR, IP2STR(&ip_info->gw));
            MDF_LOGI("~~~~~~~~~~~~~~~~~~~~~~~~~");
            #endif
            mdf_event_loop_send(MDF_EVENT_MWIFI_PARENT_CONNECTED, NULL);  // 发送到MDF事件
            break;
        }

        default:
            #ifdef TAG
            MDF_LOGI("ip_event_handler Other event_base: %s; event_id: %d", event_base, event_id);
            #endif
            break;
    }
}

esp_netif_t *get_eth_netif(void)
{
    return eth_netif;
}

//This function is called (in irq context!) just before a transmission starts. It will
//set the D/C line to the value indicated in the user field.
// void eth_spi_pre_transfer_callback(spi_transaction_t *t)
// {
//     MDF_LOGI("spi_transaction_t->flags: %d | 0x%x", t->flags, t->flags);
// }

void app_wifi_ethernet_init(void)
{
    // ESP_ERROR_CHECK(esp_netif_init());
    // ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
    eth_netif = esp_netif_new(&netif_cfg);
 
    eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
    eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
    phy_config.phy_addr = CONFIG_ETH_SPI_PHY_ADDR0;
    phy_config.reset_gpio_num = CONFIG_ETH_SPI_PHY_RST0_GPIO;
    mac_config.rx_task_prio = configMAX_PRIORITIES - 3;  // 配置以太网接收任务函数的优先级
    mac_config.rx_task_stack_size = 4096;  // 配置以太网接收任务函数的堆栈大小！ 

#if 1  // CONFIG_EXAMPLE_USE_W5500
    gpio_install_isr_service(0);
    spi_device_handle_t spi_handle = NULL;
    spi_bus_config_t buscfg = {
        .miso_io_num = CONFIG_ETH_SPI_MISO_GPIO,
        .mosi_io_num = CONFIG_ETH_SPI_MOSI_GPIO,
        .sclk_io_num = CONFIG_ETH_SPI_SCLK_GPIO,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        // .max_transfer_sz = 4096,
    };
    ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_ETH_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));

    #ifdef TAG
    MDF_LOGI("max_transfer_sz = %d", buscfg.max_transfer_sz);
    MDF_LOGI("eth_netif.route_prio = %d", esp_netif_get_route_prio(eth_netif)); 
    #endif

    spi_device_interface_config_t devcfg = {
        .command_bits = 16, // Actually it's the address phase in W5500 SPI frame
        .address_bits = 8,  // Actually it's the control phase in W5500 SPI frame
        .mode = 0,
        .clock_speed_hz = CONFIG_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
        .spics_io_num = CONFIG_ETH_SPI_CS0_GPIO,
        .queue_size = 20,
        // .post_cb = eth_spi_pre_transfer_callback,  // Specify pre-transfer callback to handle  
    };
    ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_ETH_SPI_HOST, &devcfg, &spi_handle));
    /* w5500 ethernet driver is based on spi driver */
    eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
    w5500_config.int_gpio_num = CONFIG_ETH_SPI_INT0_GPIO;
    esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
    esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config);
#endif // CONFIG_EXAMPLE_USE_W5500
    esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
    ESP_ERROR_CHECK(esp_eth_driver_install(&config, &eth_handle));

    /* The SPI Ethernet module might doesn't have a burned factory MAC address, we cat to set it manually.
       02:00:00 is a Locally Administered OUI range so should not be used except when testing on a LAN under your control.
    */
    ESP_ERROR_CHECK(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, (uint8_t[]) {
        0x02, 0x00, 0x00, 0x96, 0x08, 0x27  // ETHIP:192.168.1.104
        // 0x02, 0x00, 0x00, 0x12, 0x34, 0x56  // ETHIP:192.168.1.74
    }));
 
    ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle)));
    // Register user defined event handers
    ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, &eth_event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT,  ESP_EVENT_ANY_ID, &ip_event_handler,  NULL));
    ESP_ERROR_CHECK(esp_eth_start(eth_handle));

    // wifi_init_config_t wifi_cfg = WIFI_INIT_CONFIG_DEFAULT();
    // MDF_ERROR_ASSERT(esp_wifi_init(&wifi_cfg));
    // MDF_ERROR_ASSERT(esp_wifi_set_storage(WIFI_STORAGE_FLASH));
    // MDF_ERROR_ASSERT(esp_wifi_set_mode(WIFI_MODE_STA));
    // MDF_ERROR_ASSERT(esp_wifi_set_ps(WIFI_PS_MAX_MODEM));
    // MDF_ERROR_ASSERT(esp_mesh_set_6m_rate(false));
    // MDF_ERROR_ASSERT(esp_wifi_start());
}

